home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 52 / Amiga Format AFCD52 (Issue 136, May 2000).iso / -serious- / programming / other / diskreader / diskreader.asm < prev    next >
Assembly Source File  |  2000-02-28  |  10KB  |  523 lines

  1. ; diskreader.asm - essential functionality for game disk installers.
  2. ; © 1998-1999 Kyzer/CSG
  3.  
  4. ; FILEMODE means that no output diskfile will be used, therefore WRITE is
  5. ; dropped - instead, SAVEF is used to write individual files
  6.     IFND    FILEMODE
  7. FILEMODE=0
  8.     ENDC
  9.  
  10. ; TRACKMODE means that all tracks are DOS tracks, so the user specifies
  11. ; the trackdisk-like device on the command line, and RAWREAD/RESYNC are 
  12. ; dropped
  13.     IFND    TRACKMODE
  14. TRACKMODE=0
  15.     ENDC
  16.  
  17. ; MESSAGES means that each track read will print out its number for the
  18. ; user to see.
  19.     IFND    MESSAGES
  20. MESSAGES=0
  21.     ENDC
  22.  
  23. ; NO_INCLUDES means that no system includes are neccessary to use diskreader
  24.     IFD    NO_INCLUDES
  25. IO_COMMAND=28            ; from devices/trackdisk.i
  26. IO_FLAGS=30
  27. IO_LENGTH=36
  28. IO_DATA=40
  29. IO_OFFSET=44
  30. IOTD_SIZE=56
  31. CMD_READ=2
  32. TD_MOTOR=9
  33. TD_RAWREAD=16
  34. IOTDB_INDEXSYNC=4
  35. MODE_NEWFILE=1006        ; from dos/dos.i
  36. ERROR_NOT_A_DOS_DISK=225
  37. _LVOOpen=-30            ; from dos/dos_lib.i
  38. _LVOClose=-36
  39. _LVOWrite=-48
  40. _LVOIoErr=-132
  41. _LVOSetIoErr=-462
  42. _LVOPrintFault=-474
  43. _LVOReadArgs=-798
  44. _LVOFreeArgs=-858
  45. _LVOPutStr=-948
  46. _LVOVPrintf=-954
  47. _LVOCloseLibrary=-414        ; from exec/exec_lib.i
  48. _LVOOpenDevice=-444
  49. _LVOCloseDevice=-450
  50. _LVODoIO=-456
  51. _LVOOpenLibrary=-552
  52. _LVOCreateIORequest=-654
  53. _LVODeleteIORequest=-660
  54. _LVOCreateMsgPort=-666
  55. _LVODeleteMsgPort=-672
  56.     ELSE
  57.     include    devices/trackdisk.i
  58.     include    dos/dos.i
  59.     include    dos/dos_lib.i
  60.     include    exec/exec_lib.i
  61.     ENDC
  62.  
  63. DOSTRACKLEN=512*11
  64.  
  65. BUFFER    MACRO    ; buffername
  66. \1    equ    __trk
  67.     ENDM
  68.  
  69. FAILURE    MACRO    ; [reason]
  70.     IFEQ    NARG
  71.     suba.l    a0,a0
  72.     ELSE
  73.     lea    \1,a0
  74.     ENDC
  75.     bra    __fail
  76.     ENDM
  77.  
  78.     IFEQ    TRACKMODE
  79. RAWREAD    MACRO    ; track
  80.     lea    __trk,a0
  81.     move.l    \1,d0
  82.     bsr    __rawrd
  83.     ENDM
  84. RESYNC    MACRO    ; wordsync
  85.     lea    __trk,a0
  86.     move.l    \1,d0
  87.     bsr    __sync
  88.     ENDM
  89.     ENDC
  90. DOSREAD    MACRO    ; track
  91.     lea    __trk,a0
  92.     move.l    \1,d0
  93.     bsr    __dosrd
  94.     ENDM
  95.  
  96.     IFEQ    FILEMODE
  97. WRITE    MACRO    ; length, [offset]
  98.     IFEQ    NARG-2
  99.     lea    __trk,a0
  100.     add.l    \2,a0
  101.     ELSE
  102.     lea    __trk,a0
  103.     ENDC
  104.     move.l    \1,d0
  105.     bsr    __write
  106.     ENDM
  107. WRITEDOS MACRO    ; track
  108.     DOSREAD    \1
  109.     WRITE    #DOSTRACKLEN
  110.     ENDM
  111.  
  112.     ELSE
  113. SAVEF    MACRO    ; filename, buffer, length
  114.     lea    \1,a0
  115.     lea    \2,a1
  116.     move.l    \3,d0
  117.     bsr    __savef
  118.     ENDM
  119.     ENDC
  120.  
  121. ;------------------------------------
  122.  
  123. call    macro
  124.     jsr    _LVO\1(a6)
  125.     endm
  126.  
  127. initstk    macro    ; stack_symbol, stackreg
  128.     link    \2,#\1
  129.     move.l    sp,a0
  130. .clr\@    clr.w    (a0)+
  131.     cmp.l    a0,\2
  132.     bne.s    .clr\@
  133.     endm
  134.  
  135. stackf    MACRO    ; stack_symbol, stackelement_symbol, [size=4]
  136.     IFND    \1
  137. \1    set    0
  138.     ENDC
  139.     IFGE    NARG-3
  140. \1    set    \1-(\3)
  141.     ELSE
  142. \1    set    \1-4
  143.     ENDC
  144. \2    equ    \1
  145.     ENDM
  146.  
  147. ; create appropriate command line arguments based on FILEMODE/TRACKMODE
  148.     IFNE    FILEMODE
  149.     IFNE    TRACKMODE
  150.  
  151.     ; filemode on, trackmode on
  152.     stackf    stk, __unit
  153.     stackf    stk, __device
  154. __args=__device
  155. __nargs=2
  156. __tmpl    macro
  157.     dc.b    "DEVICE/A,UNIT/N/A",0
  158.     endm
  159.  
  160.     ELSE
  161.  
  162.     ; filemode on, trackmode off
  163.     stackf    stk, __unit
  164. __args=__unit
  165. __nargs=1
  166. __tmpl    macro
  167.     dc.b    "UNIT/N/A",0
  168.     endm
  169.  
  170.     ENDC
  171.     ELSE
  172.     IFNE    TRACKMODE
  173.  
  174.     ; filemode off, trackmode on
  175.     stackf    stk, __unit
  176.     stackf    stk, __device
  177.     stackf    stk, __output
  178. __args=__output
  179. __nargs=3
  180. __tmpl    macro
  181.     dc.b    "DISKFILE/A,DEVICE/A,UNIT/N/A",0
  182.     endm
  183.  
  184.     ELSE
  185.  
  186.     ; filemode off, trackmode off
  187.     stackf    stk, __unit
  188.     stackf    stk, __output
  189. __args=__output
  190. __nargs=2
  191. __tmpl    macro
  192.     dc.b    "DISKFILE/A,UNIT/N/A",0
  193.     endm
  194.  
  195.     ENDC
  196.     ENDC
  197.  
  198. ; other variables used
  199.  
  200.     stackf    stk, __rdargs    ; returned by ReadArgs()
  201.     stackf    stk, __diskport    ; replyport for diskio
  202.     stackf    stk, __diskio    ; IORequest to trackdisk.device
  203.     stackf    stk, __outfh    ; output filehandle (NULL in filemode)
  204.     stackf    stk, __initsp    ; initial (sp): move to sp then rts to quit
  205.     stackf    stk, __reason    ; ptr to textual reason for failure, or NULL
  206.     stackf    stk, execbase    ; exec.library
  207.     stackf    stk, dosbase    ; dos.library
  208.  
  209. ;------------------------------------
  210.  
  211.     section    diskreader,code
  212.     link    a5,#stk
  213.     move.l    4.w,a6
  214.     move.l    a6,execbase(a5)
  215.  
  216. ; no printable reason for failure, but start with errorcode
  217. ; incase we can't open DOS
  218.  
  219.     clr.l    __reason(a5)
  220.     moveq    #100,d7
  221.  
  222. ; open dos.library
  223.     moveq    #37,d0
  224.     lea    __dosnm(pc),a1
  225.     call    OpenLibrary
  226.     move.l    d0,dosbase(a5)
  227.     beq    .nodos
  228.     move.l    d0,a6
  229.  
  230. ; read arguments on command line
  231.     lea    __templ(pc),a0
  232.     move.l    a0,d1
  233.     lea    __args(a5),a0
  234.     move.l    a0,d2
  235.     REPT    __nargs
  236.     clr.l    (a0)+
  237.     ENDR
  238.     moveq    #0,d3
  239.     call    ReadArgs
  240.     move.l    d0,__rdargs(a5)
  241.     beq    .noargs
  242.  
  243. ; create the output diskfile (unless FILEMODE)
  244.     IFEQ    FILEMODE
  245.     move.l    __output(a5),d1
  246.     move.l    #MODE_NEWFILE,d2
  247.     call    Open
  248.     move.l    d0,__outfh(a5)
  249.     beq.s    .nofile
  250.     ENDC
  251.  
  252. ; open trackdisk.device (or user-specified in TRACKMODE)
  253.     move.l    execbase(a5),a6
  254.     call    CreateMsgPort
  255.     move.l    d0,__diskport(a5)
  256.     beq.s    .noport
  257.  
  258.     move.l    d0,a0
  259.     moveq    #IOTD_SIZE,d0
  260.     call    CreateIORequest
  261.     move.l    d0,__diskio(a5)
  262.     beq.s    .noio
  263.  
  264.     move.l    d0,a1
  265.     move.l    __unit(a5),a0
  266.     move.l    (a0),d0
  267.     IFNE    TRACKMODE
  268.     move.l    __device(a5),a0
  269.     ELSE
  270.     lea    __tdnm(pc),a0
  271.     ENDC
  272.     moveq    #0,d1
  273.     call    OpenDevice
  274.     tst.l    d0
  275.     bne.s    .nodev
  276.  
  277.  
  278. ;--------------------------------------
  279. ; call and return from the main 'slave'
  280.     bsr    __main
  281. ;--------------------------------------
  282.  
  283.  
  284. ; if messages mode, advance to new line for clarity
  285.     IFNE    MESSAGES
  286.     pea    10<<24    ; "\n\0\0\0"
  287.     move.l    sp,d1
  288.     move.l    dosbase(a5),a6
  289.     call    PutStr    ; print a newline
  290.     addq.l    #4,sp
  291.     ENDC
  292.  
  293. ; turn off disk motor
  294.     move.l    __diskio(a5),a1
  295.     move.w    #TD_MOTOR,IO_COMMAND(a1)
  296.     clr.l    IO_LENGTH(a1)
  297.     move.l    execbase(a5),a6
  298.     call    DoIO
  299.     
  300. ; close disk device
  301.     move.l    __diskio(a5),a1
  302.     call    CloseDevice
  303. .nodev    move.l    __diskio(a5),a0
  304.     call    DeleteIORequest
  305. .noio    move.l    __diskport(a5),a0
  306.     call    DeleteMsgPort
  307. .noport
  308.  
  309.     move.l    dosbase(a5),a6
  310.  
  311. ; close the output diskfile (if not FILEMODE)
  312.     IFEQ    FILEMODE
  313.     move.l    __outfh(a5),d1
  314.     call    Close
  315. .nofile
  316.     ENDC
  317.  
  318. ; free command-line arguments
  319.     move.l    __rdargs(a5),d1
  320.     call    FreeArgs
  321. .noargs
  322.  
  323. ; print error message if ioerror - this includes NOT_A_DOS_DISK
  324. ; if a printable reason exists, use that as the head of the printed
  325. ; error message.
  326.  
  327.     moveq    #0,d7         ; returncode = 0
  328.     call    IoErr
  329.     move.l    d0,d1
  330.     beq.s    1$
  331.     moveq    #20,d7        ; returncode = 20
  332. 1$    move.l    __reason(a5),d2
  333.     call    PrintFault
  334.  
  335. ; close dos.library and go home
  336.     move.l    a6,a1
  337.     move.l    execbase(a5),a6
  338.     call    CloseLibrary
  339. .nodos    move.l    d7,d0
  340.     unlk    a5
  341.     rts
  342.  
  343.  
  344. ; internal routine to print out track number - D0 = track
  345.     IFNE    MESSAGES
  346. __prtrk    movem.l    d0-d2/a0,-(sp)
  347.     lea    __msg(pc),a0
  348.     move.l    a0,d1
  349.     move.l    sp,d2    ; points at D0 on the stack
  350.     move.l    dosbase(a5),a6
  351.     call    VPrintf
  352.     movem.l    (sp)+,d0-d2/a0
  353.     rts
  354.     ENDC
  355.  
  356. ; if TRACKMODE, then use a complete DOSREAD routine
  357.  
  358.     IFNE    TRACKMODE
  359. ;------------------------------------
  360. ; a0 = buffer, d0 = track
  361. __dosrd    move.l    a6,-(sp)
  362.     IFNE    MESSAGES
  363.     bsr.s    __prtrk        ; print track number in messages mode
  364.     ENDC
  365.     move.l    __diskio(a5),a1
  366.     move.w    #CMD_READ,IO_COMMAND(a1)
  367.     move.l    #DOSTRACKLEN,d1
  368.     mulu    d1,d0            ; convert D0=track to D0=offset
  369.     move.l    d1,IO_LENGTH(a1)    ; D1 = length
  370.  
  371.     move.l    a0,IO_DATA(a1)
  372.     move.l    d0,IO_OFFSET(a1)
  373.     move.l    execbase(a5),a6
  374.     call    DoIO            ; read disk part
  375.     lea    __ertrk(pc),a0        ; fail with "error reading track"
  376.     tst.l    d0            ; if DoIO fails
  377.     bne.s    __fail    
  378.     move.l    (sp)+,a6
  379.     rts
  380.     ELSE
  381.  
  382. ; if not TRACKMODE, merge the common parts of RAWREAD and DOSREAD
  383.  
  384. ;------------------------------------
  385. ; a0 = buffer, d0 = track
  386. __dosrd    move.l    a6,-(sp)
  387.     IFNE    MESSAGES
  388.     bsr.s    __prtrk
  389.     ENDC
  390.     move.l    __diskio(a5),a1
  391.     move.w    #CMD_READ,IO_COMMAND(a1)
  392.     move.l    #DOSTRACKLEN,d1
  393.     mulu    d1,d0            ; as above, D0 = offset, D1 = length
  394.     move.l    d1,IO_LENGTH(a1)
  395.     bra.s    __rdcom
  396.  
  397. ;------------------------------------
  398. ; a0 = buffer, d0 = track
  399. __rawrd    move.l    a6,-(sp)
  400.     IFNE    MESSAGES
  401.     bsr.s    __prtrk
  402.     ENDC
  403.     move.l    __diskio(a5),a1
  404.     move.w    #TD_RAWREAD,IO_COMMAND(a1)
  405.     move.b    #IOTDB_INDEXSYNC,IO_FLAGS(a1)    ; just for fun...
  406.     move.l    #$7ffe,IO_LENGTH(a1)    ; here length always is maximum
  407.  
  408. __rdcom    move.l    a0,IO_DATA(a1)
  409.     move.l    d0,IO_OFFSET(a1)
  410.     move.l    execbase(a5),a6
  411.     call    DoIO            ; error handling as above
  412.     lea    __ertrk(pc),a0
  413.     tst.l    d0
  414.     bne.s    __fail
  415.     move.l    (sp)+,a6
  416.     rts
  417.     ENDC
  418.  
  419. ; FAIL will always quit out of the 'slave' and return to the main
  420. ; routine, whatever the location on the stack
  421.  
  422. ;------------------------------------
  423. ; a0 = failure reason
  424. __fail    move.l    a0,d0
  425.     beq.s    .noreas
  426.     move.l    d0,__reason(a5)
  427.     move.l    dosbase(a5),a6
  428.     move.l    #ERROR_NOT_A_DOS_DISK,d1
  429.     call    SetIoErr
  430. .noreas    move.l    __initsp(a5),sp
  431.     rts
  432.  
  433. ; in FILEMODE, there is a SAVEF which saves a whole file with its own name.
  434.  
  435.     IFNE    FILEMODE
  436. ;------------------------------------
  437. ; a0 = filename, a1 = buffer, d0 = length
  438. __savef    movem.l    d2-d4/a6,-(sp)
  439.     move.l    a0,d1
  440.     move.l    a1,d3    ; d3 = buffer
  441.     move.l    d0,d4    ; d4 = length
  442.     move.l    #MODE_NEWFILE,d2
  443.     move.l    dosbase(a5),a6
  444.     call    Open
  445.     move.l    d0,d1    ; d1 = filehandle
  446.     move.l    d3,d2    ; d2 = buffer
  447.     move.l    d4,d3    ; d3 = length
  448.     move.l    d0,d4    ; d4 = filehandle
  449.     beq.s    __fail
  450.     call    Write
  451.     move.l    d0,d3
  452.     move.l    d4,d1
  453.     call    Close
  454.     tst.l    d3
  455.     bmi.s    __fail
  456.     movem.l    (sp)+,d2-d4/a6
  457.     rts
  458.  
  459.     ELSE
  460. ; off FILEMODE, you can only write to the diskfile
  461.  
  462. ;------------------------------------
  463. ; a0 = buffer, d0 = length
  464. __write    movem.l    d2-d3/a6,-(sp)
  465.     move.l    a0,d2
  466.     move.l    d0,d3
  467.     move.l    __outfh(a5),d1
  468.     move.l    dosbase(a5),a6
  469.     call    Write
  470.     tst.l    d0
  471.     bmi.s    __fail
  472.     movem.l    (sp)+,d2-d3/a6
  473.     rts
  474.     ENDC
  475.  
  476. ; RAW tracks need to be WORDSYNCed to be readable - this routine does that
  477.  
  478.     IFEQ    TRACKMODE
  479. ;------------------------------------
  480. ; a0 = buffer d0 = sync
  481. __sync    movem.l    d2-d3,-(sp)
  482.     move.l    a0,a1
  483.     move.w    #($7ffe/2)-1,d2        ; search entire trackbuffer
  484. .nxtwrd    moveq    #16-1,d3        ; find a BIT distance...
  485. .nxtbit    move.l    (a0),d1            ; and a BYTE distance..
  486.     lsr.l    d3,d1
  487.     cmp.w    d0,d1            ; ... for which we find the SYNCWORD
  488.     beq.s    .synced
  489.     dbra    d3,.nxtbit
  490.     addq.l    #2,a0
  491.     dbra    d2,.nxtwrd
  492.     lea    .err(pc),a0        ; searched through all 32k...
  493.     bra.s    __fail            ; ...no sync marker found
  494.  
  495. .synced    move.l    (a0),d1            ; match; now we shift all the remaining
  496.     addq.l    #2,a0            ; trackdata backwards by this BIT and
  497.     lsr.l    d3,d1            ; BYTE distance, so the first word in
  498.     move.w    d1,(a1)+        ; the trackbuffer is the SYNCWORD
  499.     dbra    d2,.synced
  500.     movem.l    (sp)+,d2-d3
  501.     rts
  502. .err    dc.b    "can't find sync mark",0
  503.     ENDC
  504.  
  505. __ertrk    dc.b    "error reading track",0
  506. __dosnm    dc.b    "dos.library",0
  507. __templ    __tmpl
  508.     IFEQ    TRACKMODE
  509. __tdnm    dc.b    "trackdisk.device",0
  510.     ENDC
  511.     IFNE    MESSAGES
  512. __msg    dc.b    "reading track %ld",13,0
  513.     ENDC
  514.     cnop    0,4
  515.  
  516.     ; create 32kb CHIP BSS hunk for trackbuffer
  517.     section    trackbuf,bss,chip
  518. __trk    ds.b    $7ffe
  519.  
  520.     ; return to main code section
  521.     section    diskreader,code
  522. __main    move.l    sp,__initsp(a5)
  523.